package org.dromara.exam.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.exam.domain.dto.*;
import org.dromara.exam.domain.entity.ExamRepo;
import org.dromara.exam.domain.bo.ExamRepoBo;
import org.dromara.exam.domain.vo.ExamRepoVo;
import org.dromara.exam.domain.vo.ExamTemplateVo;
import org.dromara.exam.domain.vo.RepoInfoVo;
import org.dromara.exam.enums.TagTypeEnum;
import org.dromara.exam.mapper.ExamRepoMapper;
import org.dromara.exam.service.*;
import org.dromara.exam.util.HTTPUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 题库Service业务层处理
 *
 * @author xiyin321
 * @date 2024-04-11
 */
@RequiredArgsConstructor
@Service
public class ExamRepoServiceImpl implements IExamRepoService {

    private final ExamRepoMapper baseMapper;
    private final IExamTemplateService templateService;
    private final IExamTagService tagService;
    private final IExamTagRelService tagRelService;

    // region 查询相关方法

    /**
     * 根据ID查询题库详情
     *
     * @param repoId 题库ID
     * @return 题库视图对象
     */
    @Override
    public ExamRepoVo queryById(Long repoId) {
        return baseMapper.selectVoById(repoId);
    }

    /**
     * 分页查询题库列表
     *
     * @param bo        查询条件对象
     * @param pageQuery 分页参数
     * @return 分页数据结果
     */
    @Override
    public TableDataInfo<ExamRepoVo> queryPageList(ExamRepoBo bo, PageQuery pageQuery) {
        // 转换标签名称到标签ID
        List<Long> tagIds = tagService.convertTagsToIds(bo.getTag());
        // 构建分页查询条件
        Page<ExamRepoVo> result = baseMapper.selectRepoVoPage(pageQuery.build(), buildQueryWrapper(bo),
            tagIds, bo.getTagMatchMode());
        if (result.getTotal() == 0) {
            return TableDataInfo.build(result);
        }
        List<Long> repoIds = result.getRecords().stream().map(ExamRepoVo::getRepoId).collect(Collectors.toList());
        // 1. 查询总题数和总分
        List<TemplateCount> counts = templateService.queryTemplateCounts(repoIds);
        // 2. 查询题型分布
        List<TemplateTypeCount> typeCounts = templateService.queryTemplateTypeCounts(repoIds);
        // 3. 查询标签分布
        List<TemplateTagCount> tagCounts = tagRelService.queryTemplateTagCounts(repoIds);
        // 4. 合并结果
        result.getRecords().forEach(repo -> {
            repo.setTemplateCount(counts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).findFirst().orElse(new TemplateCount()));
            repo.getTemplateCount().setQuestionTypeCount(typeCounts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).collect(Collectors.toList()));
            repo.getTemplateCount().setTagCount(tagCounts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).collect(Collectors.toList()));
        });
        return TableDataInfo.build(result);
    }

    /**
     * 查询题库列表（非分页）
     *
     * @param bo 查询条件对象
     * @return 题库视图列表
     */
    @Override
    public List<ExamRepoVo> queryList(ExamRepoBo bo) {
        LambdaQueryWrapper<ExamRepo> lqw = buildLambdaQueryWrapper(bo);
        List<ExamRepoVo> list = baseMapper.selectVoList(lqw);
        if (list.isEmpty()) {
            return list;
        }
        List<Long> repoIds = list.stream().map(ExamRepoVo::getRepoId).toList();
        // 1. 查询总题数和总分
        List<TemplateCount> counts = templateService.queryTemplateCounts(repoIds);
        // 2. 查询题型分布
        List<TemplateTypeCount> typeCounts = templateService.queryTemplateTypeCounts(repoIds);
        // 3. 查询标签分布
        List<TemplateTagCount> tagCounts = tagRelService.queryTemplateTagCounts(repoIds);
        // 4. 合并结果
        list.forEach(repo -> {
            repo.setTemplateCount(counts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).findFirst().orElse(new TemplateCount()));
            repo.getTemplateCount().setQuestionTypeCount(typeCounts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).collect(Collectors.toList()));
            repo.getTemplateCount().setTagCount(tagCounts.stream().filter(count -> count.getRepoId().equals(repo.getRepoId())).collect(Collectors.toList()));
        });
        return list;
    }

    /**
     * 构建Lambda查询条件
     *
     * @param bo 查询条件对象
     * @return Lambda查询包装器
     */
    private LambdaQueryWrapper<ExamRepo> buildLambdaQueryWrapper(ExamRepoBo bo) {
        LambdaQueryWrapper<ExamRepo> lqw = Wrappers.lambdaQuery();
        // 按题库名称模糊查询
        lqw.like(StringUtils.isNotEmpty(bo.getRepoName()), ExamRepo::getRepoName, bo.getRepoName());
        // 按共享标志精确查询
        lqw.eq(StringUtils.isNotEmpty(bo.getShareFlag()), ExamRepo::getShareFlag, bo.getShareFlag());
        return lqw;
    }

    /**
     * 构建原生查询条件（用于复杂分页查询）
     *
     * @param bo 查询条件对象
     * @return 查询包装器
     */
    private Wrapper<ExamRepo> buildQueryWrapper(ExamRepoBo bo) {
        QueryWrapper<ExamRepo> wrapper = Wrappers.query();
        wrapper
            .eq("r.del_flag", "0")
            .like(StringUtils.isNotBlank(bo.getRepoName()), "r.repo_name", bo.getRepoName());
        return wrapper;
    }

    // endregion

    // region 新增相关方法

    /**
     * 新增题库
     *
     * @param bo 题库业务对象
     * @return 操作结果
     */
    @Override
    public Boolean insertByBo(ExamRepoBo bo) {
        ExamRepo entity = MapstructUtils.convert(bo, ExamRepo.class);
//        validateBeforeSave(entity);

        boolean success = baseMapper.insert(entity) > 0;
        if (success && bo.getTag().length > 0) {
            bo.setRepoId(entity.getRepoId());
            // 处理关联标签
            tagService.processTags(bo.getRepoId(), TagTypeEnum.RepoType, bo.getTag());
        }
        return success;
    }

    // endregion

    // region 修改相关方法

    /**
     * 修改题库信息
     *
     * @param bo 题库业务对象
     * @return 操作结果
     */
    @Override
    public Boolean updateByBo(ExamRepoBo bo) {
        ExamRepo entity = MapstructUtils.convert(bo, ExamRepo.class);
        validateBeforeSave(entity);
        return baseMapper.updateById(entity) > 0;
    }

    /**
     * 保存前的数据校验及预处理
     *
     * @param entity 题库实体对象
     */
    private void validateBeforeSave(ExamRepo entity) {
        if (ObjectUtil.isNotNull(entity.getTag())) {
            // 清除旧标签关联
            tagRelService.batchDeleteByRelIds(Collections.singleton(entity.getRepoId()));
            // 处理新标签关联
            tagService.processTags(entity.getRepoId(), TagTypeEnum.RepoType, entity.getTag());
        }
    }

    // endregion

    // region 删除相关方法

    /**
     * 批量删除题库
     *
     * @param ids     待删除ID集合
     * @param isValid 是否进行关联校验
     * @return 操作结果
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // 删除关联的标签数据
            tagRelService.batchDeleteByRelIds(ids);
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    // endregion

    // region 其他业务方法

    /**
     * 下载题库导入模板
     *
     * @param templateName 模板名称（不含后缀）
     * @return 文件资源响应实体
     */
    @Override
    public ResponseEntity<Resource> downloadTemplate(String templateName) {
        String fullName = templateName + ".xlsx";
        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, HTTPUtils.getContentDispositionValue(fullName))
            .contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
            .body(new ClassPathResource("template/" + fullName));
    }

    /**
     * 从题库中抽取试题
     *
     * @param conditions 随机抽题条件集合
     * @return 按顺序排列的项目结构列表
     */
    @Override
    public List<TemplateSchema> pickTemplateFromRepo(List<ProjectSetting.RandomQuestionCondition> conditions) {
        List<ExamTemplateVo> selectedQuestions = new ArrayList<>();

        conditions.forEach(condition -> {
            // 根据条件查询候选题目
            List<ExamTemplateVo> candidates = templateService.pickTemplateList(
                condition.getRepoId(),
                condition.getQuestionTypes(),
                condition.getTags()
            );

            // 执行随机抽题
            if (ObjectUtil.isNotNull(condition.getNum())) {
                Collections.shuffle(candidates);
                if (candidates.size() > condition.getNum()) {
                    candidates = candidates.subList(0, condition.getNum());
                }
            }

            // 处理题目分数并去重
            candidates.forEach(question -> {
                if (selectedQuestions.stream()
                    .anyMatch(exist -> exist.getTemplateId().equals(question.getTemplateId()))) {
                    return;
                }

                if (ObjectUtil.isNotNull(condition.getScore())) {
                    // 初始化题目属性对象
                    if (question.getTemplate().getAttribute() == null) {
                        question.getTemplate().setAttribute(new TemplateSchema.Attribute());
                    }
                    question.getTemplate().getAttribute().setExamScore(condition.getScore());
                }
                selectedQuestions.add(question);
            });
        });

        // 按题型排序返回
        return selectedQuestions.stream()
            .map(question -> {
                TemplateSchema schema = question.getTemplate();
                schema.setId(String.valueOf(question.getTemplateId()));
                return schema;
            })
            .sorted(Comparator.comparing(TemplateSchema::getOrderNum))
            .collect(Collectors.toList());
    }

    /**
     * 查询题库列表（包含模板）
     *
     * @param bo 题库业务对象
     * @return 题库视图列表
     */
    @Override
    public List<RepoInfoVo> queryListAndTemplate(ExamRepoBo bo) {
        QueryWrapper<ExamRepo> wrapper = Wrappers.query();
        wrapper
            .eq("r.del_flag", "0")
            .eq("t.del_flag", "0")
            .like(StringUtils.isNotBlank(bo.getRepoName()), "r.repo_name", bo.getRepoName());
        List<RepoInfoVo> list = baseMapper.queryListAndTemplate(wrapper);
        list.add(baseMapper.queryListAndTemplateByUnion());
        // 过滤null
        list.removeIf(Objects::isNull);
        return list;
    }

    // endregion

}
